﻿using LxBasic;
using LxCore;
using LxLESS;
using System.Text;
using System.Xml.Linq;

namespace LxCore
{
    public class FvZone : JsIdentifyItem, IBuildMGZone
    {
        public FvZone()
        {
            Name = "新区域";
            this.Inner = new FvInner(this);
        }
        public Vector3d[] Nodes;
        public FvInnFace[] InnFaces;
        public FvInnCell[] InnCells;
        public FvBouFace[] BouFaces;

        public double[] InnCellInnFaceShare;
        public double[] InnCellBouFaceShare;

        public LESSZone LESSZone { get; set; }
        public FvInner Inner { get; set; }
        public FvBoundList Bounds { get; private set; } = new();

        #region 几何模型   
        public void CheckCreate()
        {
            if (LESSZone != null) return;
            //protected void CreatCells()
            {
                AssignFaceToCellTool at = new AssignFaceToCellTool(InnCells.Length, InnFaces.Length, BouFaces.Length);
                for (int i1 = 0; i1 < InnFaces.Length; i1++)
                {
                    ref var f = ref InnFaces[i1];
                    at.AssignInnFaceToCell(f.OSideCell, f.NSideCell, i1);
                }
                for (int i1 = 0; i1 < BouFaces.Length; i1++)
                {
                    ref var f = ref BouFaces[i1];
                    at.AssignBouFacesToCell(f.OSideCell, i1);
                }
                //CheckCreator.ArrayStrict(ref InnCells, Inner.CellIdx.GetCount());
                for (int i1 = 0; i1 < InnCells.Length; i1++)
                {
                    ref var c = ref InnCells[i1];
                    (c.AdjFaces, c.InnOFaceEnd, c.InnNFaceEnd) = at.GetFaces(i1);
                }
            }
            //protected void CalZoneGeometry()
            {
                for (int i2 = 0; i2 < InnFaces.Length; i2++)
                {
                    InnFaces[i2].CalGeometryInFace(Nodes);
                }
                for (int i2 = 0; i2 < BouFaces.Length; i2++)
                {
                    BouFaces[i2].CalGeometryInFace(Nodes);
                }
                for (int i2 = 0; i2 < InnCells.Length; i2++)
                {
                    InnCells[i2].CalGeometry(InnFaces, BouFaces);
                }
                for (int i2 = 0; i2 < InnFaces.Length; i2++)
                {
                    InnFaces[i2].CalGeometryAcrossInnFace(InnCells);
                }
                for (int i2 = 0; i2 < BouFaces.Length; i2++)
                {
                    BouFaces[i2].CalGeometryAcrossBouFace(InnCells);
                }
                for (int i2 = 0; i2 < InnCells.Length; i2++)
                {
                    InnCells[i2].CalLSQMatrix(InnFaces, BouFaces);
                }
            }
            //protected void CalTotalVolumnArea()
            {
                double vol = 0;
                for (int i1 = Inner.CellIdx.Start; i1 < Inner.CellIdx.End; i1++)
                {
                    vol += InnCells[i1].Volumn;
                }
                Inner.Volumn = vol;
                for (int i2 = 0; i2 < Bounds.Count; i2++)
                {
                    double area = 0;
                    var b = Bounds[i2];
                    for (int i3 = b.FaceIdx.Start; i3 < b.FaceIdx.End; i3++)
                    {
                        area += BouFaces[i3].Area;
                    }
                    b.Area = area;
                }
            }
            CheckCreator.ArrayStrict(ref InnCellInnFaceShare, Math.Max(InnCells.Length, InnFaces.Length));
            CheckCreator.ArrayStrict(ref InnCellBouFaceShare, Math.Max(InnCells.Length, BouFaces.Length));
            {
                LESSZone = new LESSZone();
                var lessset = LxSim.Sim.Mesh.LessSetting;
                LESSZone.CheckCreate(this, lessset.AMGGroupCount, -1, new List<double[]>() { InnCellInnFaceShare, InnCellBouFaceShare });
            }

        }
        public void ResetMesh()
        {
            throw new NotImplementedException();
        }
        public void CheckTopology()
        {
            //统计面的数量
            int count = 0;
            foreach (var c in InnCells)
            {
                count += c.AdjFaces.Length;
            }
            if (count != (2 * InnFaces.Length + BouFaces.Length))
            {
                throw new Exception("CheckTopologyError:面数量对不上");
            }
            for (int i1 = 0; i1 < InnCells.Length; i1++)
            {
                ref var c = ref InnCells[i1];
                int i2 = 0;
                for (; i2 < c.InnOFaceEnd; i2++)
                {
                    if (InnFaces[c.AdjFaces[i2]].OSideCell != i1)
                    {
                        throw new Exception("CheckTopologyError:序号对不上");
                    }
                }
                for (; i2 < c.InnNFaceEnd; i2++)
                {
                    if (InnFaces[c.AdjFaces[i2]].NSideCell != i1)
                    {
                        throw new Exception("CheckTopologyError:序号对不上");
                    }
                }
                for (; i2 < c.AdjFaces.Length; i2++)
                {
                    if (BouFaces[c.AdjFaces[i2]].OSideCell != i1)
                    {
                        throw new Exception("CheckTopologyError:序号对不上");
                    }
                }
            }
            //检查负体积



            //统计网格Cell的面数
            {
                int max = 0;
                int min = int.MaxValue;
                foreach (var c in InnCells)
                {
                    int m = c.AdjFaces.Length;
                    if (m > max) max = m;
                    if (m < min) min = m;
                }
                //LxLog.Info($"面数 {min}-{max}");
            }
            //检查giff负数
            {
                StringBuilder stringBuilder = new StringBuilder($"检查 {ID} {Name} 区域网格出错，O2N和Normal方向相反：");
                int iniLen = stringBuilder.Length;
                for (int i1 = 0; i1 < InnFaces.Length; i1++)
                {
                    if (InnFaces[i1].gDiff <= 0)
                    {
                        stringBuilder.Append($",Inn {i1}");
                    }
                }
                for (int i1 = 0; i1 < BouFaces.Length; i1++)
                {
                    if (BouFaces[i1].gDiff <= 0)
                    {
                        stringBuilder.Append($",Bou {i1}");
                    }
                }
                if (stringBuilder.Length != iniLen)
                {
                    LxLog.Error(stringBuilder.ToString());
                }
            }

        }
        #endregion
        //多重网格接口
        IEnumerable<int> IBuildMGZone.GetInnCellAdjInnCelll(int cellId)
        {
            var c = InnCells[cellId];
            for (int i1 = c.InnOFaceEnd; i1 < c.InnNFaceEnd; i1++)
            {
                yield return InnFaces[c.AdjFaces[i1]].OSideCell;
            }
            for (int i1 = 0; i1 < c.InnOFaceEnd; i1++)
            {
                yield return InnFaces[c.AdjFaces[i1]].NSideCell;
            }
        }
        int IBuildMGZone.GetBoundsCount() => Bounds.Count;
        public (int OSideCell, int NSideCell) GetInnFaceAdjCell(int faceID)
        {
            ref var f = ref InnFaces[faceID];
            return (f.OSideCell, f.NSideCell);
        }


        (int OSideCell, int NSideCell) IBuildMGZone.GetInnFaceAdjCell(int faceID)
        {
            ref var f = ref InnFaces[faceID];
            return (f.OSideCell, f.NSideCell);
        }

        int IBuildMGZone.GetBouFaceOSideCell(int bouFaceId)
        {
            return BouFaces[bouFaceId].OSideCell;
        }

        (IndexRange CellIdx, IndexRange FaceIdx) IBuildMGZone.GetInnerIdx()
        {
            return (Inner.CellIdx, Inner.FaceIdx);
        }

        IndexRange IBuildMGZone.GetBoundIdx(int boundID)
        {
            return Bounds[boundID].FaceIdx;
        }
        public override void FromJsonKV(string key, IJsonReader jsReader)
        {
            switch (key)
            {
                case nameof(Nodes): jsReader.ReadVector3dArray(Nodes, e => Nodes = e); break;
                case nameof(InnFaces): jsReader.ReadInnFaceArray(InnFaces, e => InnFaces = e); break;
                case nameof(BouFaces): jsReader.ReadBouFaceArray(BouFaces, e => BouFaces = e); break;
                case nameof(InnCells): CheckCreator.ArrayStrict(ref InnCells, jsReader.ReadInt()); break;
                case nameof(Inner): jsReader.ReadObject(Inner); break;
                case nameof(Bounds): jsReader.ReadList(Bounds, (t) => new FvBound(this)); break;
                default: base.FromJsonKV(key, jsReader); break;
            }
        }
        public override void ToJsonKV(IJsonWriter jsWriter)
        {
            base.ToJsonKV(jsWriter);
            jsWriter.WriteVector3dArray(nameof(Nodes), Nodes);
            jsWriter.WriteInnFaceArray(nameof(InnFaces), InnFaces);
            jsWriter.WriteBouFaceArray(nameof(BouFaces), BouFaces);
            jsWriter.WriteInt(nameof(InnCells), InnCells.Length);
            jsWriter.WriteObject(nameof(Inner), Inner);
            jsWriter.WriteList(nameof(Bounds), Bounds);
        }

    }
}
//public void CheckCreate()
//{
//   
//    //protected void CreatCells()
//    {
//        AssignFaceToCellTool at = new AssignFaceToCellTool(InnCells.Length, InnFaces.Length, BouFaces.Length);
//        for (int i1 = 0; i1 < InnFaces.Length; i1++)
//        {
//            ref var f = ref InnFaces[i1];
//            at.AssignInnFaceToCell(f.OSideCell, f.NSideCell, i1);
//        }
//        for (int i1 = 0; i1 < BouFaces.Length; i1++)
//        {
//            ref var f = ref BouFaces[i1];
//            at.AssignBouFacesToCell(f.OSideCell, i1);
//        }
//        //CheckCreator.ArrayStrict(ref InnCells, Inner.CellIdx.GetCount());
//        for (int i1 = 0; i1 < InnCells.Length; i1++)
//        {
//            ref var c = ref InnCells[i1];
//            (c.AdjFaces, c.InnOFaceEnd, c.InnNFaceEnd) = at.GetFaces(i1);
//        }
//    }
//    //protected void CalZoneGeometry()
//    {
//        for (int i2 = 0; i2 < InnFaces.Length; i2++)
//        {
//            InnFaces[i2].CalGeometryInFace(Nodes);
//        }
//        for (int i2 = 0; i2 < BouFaces.Length; i2++)
//        {
//            BouFaces[i2].CalGeometryInFace(Nodes);
//        }
//        for (int i2 = 0; i2 < InnCells.Length; i2++)
//        {
//            InnCells[i2].CalGeometry(InnFaces, BouFaces);
//        }
//        for (int i2 = 0; i2 < InnFaces.Length; i2++)
//        {
//            InnFaces[i2].CalGeometryAcrossInnFace(InnCells);
//        }
//        for (int i2 = 0; i2 < BouFaces.Length; i2++)
//        {
//            BouFaces[i2].CalGeometryAcrossBouFace(InnCells);
//        }
//        for (int i2 = 0; i2 < InnCells.Length; i2++)
//        {
//            InnCells[i2].CalLSQMatrix(InnFaces, BouFaces);
//        }
//    }
//    //protected void CalTotalVolumnArea()
//    {
//        double vol = 0;
//        for (int i1 = Inner.CellIdx.Start; i1 < Inner.CellIdx.End; i1++)
//        {
//            vol += InnCells[i1].Volumn;
//        }
//        Inner.Volumn = vol;
//        for (int i2 = 0; i2 < Bounds.Count; i2++)
//        {
//            double area = 0;
//            var b = Bounds[i2];
//            for (int i3 = b.FaceIdx.Start; i3 < b.FaceIdx.End; i3++)
//            {
//                area += BouFaces[i3].Area;
//            }
//            b.Area = area;
//        }
//    }
//    CheckCreator.ArrayStrict(ref InnCellInnFaceShare, Math.Max(InnCells.Length, InnFaces.Length));
//    CheckCreator.ArrayStrict(ref InnCellBouFaceShare, Math.Max(InnCells.Length, BouFaces.Length));
//    {
//        LESSZone = new LESSZone();
//        var lessset = LxSim.Sim.Mesh.LessSetting;
//        LESSZone.CheckCreate(this, lessset.AMGGroupCount, -1, new List<double[]>() { InnCellInnFaceShare, InnCellBouFaceShare });
//    }

//}
